package com.zhiyu.service.impl;

import com.zhiyu.entity.DO.AccountDO;
import com.zhiyu.entity.DO.PermissionDO;
import com.zhiyu.entity.DO.RoleDO;
import com.zhiyu.entity.DO.UserDO;
import com.zhiyu.entity.DTO.FollowListUserInfoDTO;
import com.zhiyu.entity.DTO.UserInfoDTO;
import com.zhiyu.entity.VO.ResponseVO;
import com.zhiyu.mapper.PermissionMapper;
import com.zhiyu.mapper.RoleMapper;
import com.zhiyu.mapper.UserMapper;
import com.zhiyu.service.RedisService;
import com.zhiyu.service.UserService;
import com.zhiyu.util.MapBuilder;
import com.zhiyu.util.ResponseUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private ResponseUtil responseUtil;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private RedisService redisService;

    @Value("${static-resource.img.avatar.default}")
    private String defaultAvatar;

    @Value("${spring.redis.key.prefix.relationship.following}")
    private String followingPrefix;

    @Value("${spring.redis.key.prefix.relationship.follower}")
    private String followerPrefix;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserDO addNewUser(int accountId) throws Exception {
        try {
            UserDO userDO = new UserDO();

            userDO.setNickname(generateInitNickname());
            userDO.setGender(-1); //默认性别为-1，即未知
            userDO.setAvatar(defaultAvatar);
            userDO.setIntroduction("");
            userDO.setHabitation("");
            userDO.setProfession("");
            userDO.setEducation("");
            userDO.setBrief("");
            AccountDO accountDO = new AccountDO();
            accountDO.setId(accountId);
            userDO.setAccount(accountDO);

            userMapper.insert(userDO);
            return userDO;
        } catch (Exception e) {
            throw new Exception();  //自动回滚
        }
    }

    @Override
    public UserDO findById(int id) {
        return userMapper.findById(id);
    }

    @Override
    public boolean checkUser(int id) {
        return userMapper.findById(id) != null;
    }

    @Override
    public UserDO findByAccountId(int accountId) {
        return userMapper.findByAccountId(accountId);
    }

    @Override
    public List<String> findRoles(int id) {
        List<RoleDO> roles = roleMapper.findAllRolesOfUser(id);
        List<String> rolesList = new ArrayList<String>();

        for (RoleDO role : roles)
            rolesList.add(role.getName());

        return rolesList;
    }

    @Override
    public List<PermissionDO> findPermissions(int id) {
        return permissionMapper.findAllPermissionsOfUser(id);
    }

    @Override
    public ResponseVO getUserInformation(int myId, int userId) {
        UserDO userDO = userMapper.findById(userId);

        if (userDO == null)
            return responseUtil.invalidResource();

        String userFollowersSet = followerPrefix + userId;
        long followersCount = redisService.getSetSize(userFollowersSet);

        String userFollowingsSet = followingPrefix + userId;
        long followingsCount = redisService.getSetSize(userFollowingsSet);

        boolean isFollowing = false;
        boolean isFollowed = false;
        if (myId != userId) {
            //查看主体用户是否关注了目标用户
            if (redisService.isSetMember(userFollowersSet, String.valueOf(myId)))
                isFollowing = true;
            //查看主体用户是否被目标用户关注
            if (redisService.isSetMember(userFollowingsSet, String.valueOf(myId)))
                isFollowed = true;
        }

        UserInfoDTO userInfoDTO = new UserInfoDTO(userDO.getId(), userDO.getNickname(), userDO.getGender(), userDO.getAvatar(),
                userDO.getBrief(), userDO.getIntroduction(), userDO.getHabitation(), userDO.getProfession(), userDO.getEducation(),
                (int) followingsCount, (int) followersCount, isFollowing, isFollowed);
        ResponseVO responseVO = responseUtil.success();
        responseVO.setData(userInfoDTO);

        return responseVO;
    }

    @Override
    public ResponseVO updateUserInformation(int userId, String field, String value) {
        UserDO userDO = userMapper.findById(userId);
        boolean flag;

        if (field.equals("nickname")) {
            if (value.length() > 0 && value.length() <= 20) {
                flag = true;
                userDO.setNickname(value);
            } else {
                flag = false;
            }
        } else if (field.equals("brief")) {
            if (value.length() > 0 && value.length() <= 100) {
                flag = true;
                userDO.setBrief(value);
            } else {
                flag = false;
            }
        } else if (field.equals("gender")) {
            int genderInt = Integer.valueOf(value);
            if (genderInt == 0 || genderInt == 1) {
                flag = true;
                userDO.setGender(Integer.valueOf(value));
            } else {
                flag = false;
            }
        } else if (field.equals("habitation")) {
            if (value.length() > 0 && value.length() <= 20) {
                flag = true;
                userDO.setHabitation(value);
            } else {
                flag = false;
            }
        } else if (field.equals("profession")) {
            if (value.length() > 0 && value.length() <= 20) {
                flag = true;
                userDO.setProfession(value);
            } else {
                flag = false;
            }
        } else if (field.equals("education")) {
            if (value.length() > 0 && value.length() <= 100) {
                flag = true;
                userDO.setEducation(value);
            } else {
                flag = false;
            }
        } else if (field.equals("introduction")) {
            if (value.length() > 0 && value.length() <= 1000) {
                flag = true;
                userDO.setIntroduction(value);
            } else {
                flag = false;
            }
        } else {
            flag = false;
        }

        if (flag) {
            userMapper.update(userDO);
            ResponseVO responseVO = responseUtil.success();
            responseVO.setData(userDO);

            return responseVO;
        } else {
            return responseUtil.fieldInvalid();
        }
    }

    @Override
    public ResponseVO follow(int myId, int userId) {
        if (!checkUser(userId) || myId == userId)
            return responseUtil.invalidResource();

        //在关注者的关注列表添加被关注者的id
        String myFollowingsSet = followingPrefix + myId;
        redisService.addIntoSet(myFollowingsSet, String.valueOf(userId));

        //在被关注者的粉丝列表添加关注者的id
        String userFollowersSet = followerPrefix + userId;
        redisService.addIntoSet(userFollowersSet, String.valueOf(myId));

        //获取被关注者的最新粉丝数并返回
        long followersCount = redisService.getSetSize(userFollowersSet);
        ResponseVO responseVO = responseUtil.success();
        responseVO.setData(MapBuilder.newInstance().put("followersCount", followersCount).build());

        return responseVO;
    }

    @Override
    public ResponseVO unfollow(int myId, int userId) {
        if (!checkUser(userId) || myId == userId)
            return responseUtil.invalidResource();

        //在关注者的关注列表删除被关注者的id
        String myFollowingsSet = followingPrefix + myId;
        redisService.removeFromSet(myFollowingsSet, String.valueOf(userId));

        //在被关注者的粉丝列表删除关注者的id
        String userFollowersSet = followerPrefix + userId;
        redisService.removeFromSet(userFollowersSet, String.valueOf(myId));

        //获取被关注者的最新粉丝数并返回
        long followersCount = redisService.getSetSize(userFollowersSet);
        ResponseVO responseVO = responseUtil.success();
        responseVO.setData(MapBuilder.newInstance().put("followersCount", followersCount).build());

        return responseVO;
    }

    @Override
    public ResponseVO getFollowers(int myId, int userId, int offset, int limit) {
        if (!checkUser(userId))
            return responseUtil.invalidResource();

        String userFollowersSet = followerPrefix + userId;
        Set<String> set = redisService.getSetMembers(userFollowersSet);

        List<FollowListUserInfoDTO> followers = new ArrayList<FollowListUserInfoDTO>();

        Iterator<String> itr = set.iterator();
        int skip = 0;
        while (skip < offset)    //找到偏移处
            itr.next();

        int count = 0;
        while (count < limit && itr.hasNext()) { //开始找limit个用户
            String targetId = itr.next();
            UserDO targetUserDO = userMapper.findById(Integer.valueOf(targetId));

            if (targetUserDO == null)
                continue;

            boolean isFollowing = false;
            boolean isFollowed = false;

            String targetUserFollowingsSet = followingPrefix + targetId;
            String targetUserFollowersSet = followerPrefix + targetId;

            if (myId != -1) {
                if (redisService.isSetMember(targetUserFollowingsSet, String.valueOf(myId)))
                    isFollowed = true;
                if (redisService.isSetMember(targetUserFollowersSet, String.valueOf(myId)))
                    isFollowing = true;
            }

            long followersCount = redisService.getSetSize(targetUserFollowersSet);

            FollowListUserInfoDTO followListUserInfoDTO = new FollowListUserInfoDTO(targetUserDO.getId(),
                    targetUserDO.getNickname(), targetUserDO.getBrief(), 0, (int) followersCount,
                    targetUserDO.getAvatar(), isFollowing, isFollowed);

            followers.add(followListUserInfoDTO);
            count++;
        }

        ResponseVO responseVO = responseUtil.success();
        responseVO.setData(MapBuilder.newInstance().put("followers", followers).build());

        return responseVO;
    }

    @Override
    public ResponseVO getFollowings(int myId, int userId, int offset, int limit) {
        if (!checkUser(userId))
            return responseUtil.invalidResource();

        String userFollowingsSet = followingPrefix + userId;
        Set<String> set = redisService.getSetMembers(userFollowingsSet);

        List<FollowListUserInfoDTO> followers = new ArrayList<FollowListUserInfoDTO>();

        Iterator<String> itr = set.iterator();
        int skip = 0;
        while (skip < offset)    //找到偏移处
            itr.next();

        int count = 0;
        while (count < limit && itr.hasNext()) { //开始找limit个用户
            String targetId = itr.next();
            UserDO targetUserDO = userMapper.findById(Integer.valueOf(targetId));

            if (targetUserDO == null)
                continue;

            boolean isFollowing = false;
            boolean isFollowed = false;

            String targetUserFollowingsSet = followingPrefix + targetId;
            String targetUserFollowersSet = followerPrefix + targetId;

            if (myId != -1) {
                if (redisService.isSetMember(targetUserFollowingsSet, String.valueOf(myId)))
                    isFollowed = true;
                if (redisService.isSetMember(targetUserFollowersSet, String.valueOf(myId)))
                    isFollowing = true;
            }

            long followersCount = redisService.getSetSize(targetUserFollowersSet);

            FollowListUserInfoDTO followListUserInfoDTO = new FollowListUserInfoDTO(targetUserDO.getId(),
                    targetUserDO.getNickname(), targetUserDO.getBrief(), 0, (int) followersCount,
                    targetUserDO.getAvatar(), isFollowing, isFollowed);

            followers.add(followListUserInfoDTO);
            count++;
        }

        ResponseVO responseVO = responseUtil.success();
        responseVO.setData(MapBuilder.newInstance().put("followers", followers).build());

        return responseVO;
    }

    /**
     * 随机生成一个nickname，取uuid的前8位作为随机字符串
     *
     * @return 昵称
     */
    private String generateInitNickname() {
        String randomString = UUID.randomUUID().toString().substring(0, 8);
        return "zhiyu_" + randomString;
    }
}
